package com.ibl.rover.lite.client.Sync.Parser;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;

import com.ibl.rover.lite.client.Sync.Parser.SyncEntity.OperationType;

import android.content.Context;

public class SyncXMLParser {

	public interface UpdateObserver {
		void onStartDocument();

		void onUpdate(String entityName, OperationType opType,
				List<Map<String, String>> attributeSet);

		void onEndDocument();
	}

	private SyncXmlData syncXmlData;
	private Context activityContext;
	private int batchSize;
	private String syncXmlPath;
	private UpdateObserver observer;

	public SyncXMLParser(Context activityContext, final int batchSize,
			final UpdateObserver observer, final String syncXmlPath) {
		this.syncXmlPath = syncXmlPath;
		this.activityContext = activityContext;
		this.batchSize = batchSize;
		this.observer = observer;
	}

	public void parse() {
		try {
			SAXParserFactory spf = SAXParserFactory.newInstance();
			SAXParser sp = spf.newSAXParser();
			syncXmlData = new SyncXmlData(batchSize, observer);
			XMLReader xr = sp.getXMLReader();
			xr.setContentHandler(syncXmlData);
			InputStream stream = activityContext.openFileInput(syncXmlPath);

			xr.parse(new InputSource(stream));
			stream.close();

		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}

	public List<SyncEntity> getSyncEntityList() {
		return syncXmlData.getSyncEntityList();
	}

	public static class SyncXmlData extends DefaultHandler {

		private static final String HEAD = "HEAD";
		private static final String RESPONSE_MESSAGE = "responseMessage";
		private static final String RESPONSE_CODE = "responseCode";
		private static final String VALUE = "value";
		private static final String ENTITY = "entity";
		private static final String NAME = "name";

		private static final String ATTRIBUTE = "attribute";
		private static final String ITEM = "item";
		private static final String ADD = "add";

		private int batchSize = 0;
		private UpdateObserver observer = null;

		// sync entity
		private SyncEntity syncEntity;

		// attribute of an entity
		private Map<String, String> entityAttributes;

		// list of attributes of an entity
		private List<Map<String, String>> entityAttributesList;

		// operation type
		private OperationType opType;

		private Map<OperationType, List<Map<String, String>>> entityListWithOp;

		private List<SyncEntity> syncEntityList;
		private ServerResponse serverResponse;

		public SyncXmlData(final int batchSize, final UpdateObserver observer) {
			this.batchSize = batchSize;
			this.observer = observer;
		}

		public ServerResponse getServerResponse() {
			return serverResponse;
		}

		@Override
		public void startDocument() throws SAXException {
			syncEntityList = new ArrayList<SyncEntity>();
			observer.onStartDocument();
			super.startDocument();
		}

		@Override
		public void endDocument() throws SAXException {
			observer.onEndDocument();
			super.endDocument();
		}

		@Override
		public void startElement(String uri, String localName, String qName,
				Attributes attributes) throws SAXException {
			if (localName.equalsIgnoreCase(HEAD)) {
				serverResponse = new ServerResponse();
			} else if (localName.equalsIgnoreCase(RESPONSE_MESSAGE)) {
				String respMsg = attributes.getValue(VALUE);
				serverResponse.setResponseMessage(respMsg);
			} else if (localName.equalsIgnoreCase(RESPONSE_CODE)) {
				String respCode = attributes.getValue(VALUE);
				serverResponse.setResponseCode(respCode);
			} else if (localName.equalsIgnoreCase(ADD)) {
				opType = OperationType.EAdd;
				entityAttributesList = new ArrayList<Map<String, String>>();
			} else if (localName.equalsIgnoreCase(ITEM)) {
				entityAttributes = new HashMap<String, String>();
			} else if (localName.equalsIgnoreCase(ENTITY)) {
				syncEntity = new SyncEntity();
				syncEntity.setName(attributes.getValue(NAME));

				entityListWithOp = new HashMap<SyncEntity.OperationType, List<Map<String, String>>>();
			} else if (localName.equalsIgnoreCase(ATTRIBUTE)) {
				String name = attributes.getValue(NAME);
				String value = attributes.getValue(VALUE);
				entityAttributes.put(name, value);
			}

		}

		@Override
		public void endElement(String uri, String localName, String qName)
				throws SAXException {
			if (localName.equalsIgnoreCase(ENTITY)) {
				syncEntity.setSyncEntity(entityListWithOp);
				syncEntityList.add(syncEntity);
			} else if (localName.equalsIgnoreCase(ITEM)) {
				entityAttributesList.add(entityAttributes);
				if (batchSize == entityAttributesList.size()) {
					observer.onUpdate(syncEntity.getName(), opType,
							entityAttributesList);
					entityAttributesList.clear();
				}
			} else if (localName.equalsIgnoreCase(ADD)) {
				if (batchSize > entityAttributesList.size()) {
					observer.onUpdate(syncEntity.getName(), opType,
							entityAttributesList);
					entityAttributesList.clear();
				}
			}
		}

		public List<SyncEntity> getSyncEntityList() {
			return syncEntityList;
		}

	}

}
